using System;
namespace fuzzyKittenVNC
{
	public abstract class AbstractRFBEncoding {
		public string type;
		public byte[] pixels;

		public static AbstractRFBEncoding fromStream(uint h, uint w, int bpp, int offset, byte[] stream) {
			return null;
		}
		
		public static uint getRequiredStreamSize(uint h, uint w, int bpp) {			
			return 0;	
		}
	};
	
	public class RFBEncoding
	{
		public class CopyRect : AbstractRFBEncoding {
			public new string type = "CopyRect";
			public int x;
			public int y;
			public new static CopyRect fromStream(uint h, uint w, int bpp, int offset, byte[] stream) {
				CopyRect Encoding = new CopyRect();
				int length =(int) 4;
				Encoding.x = stream[offset]<<8&stream[offset+1];
				Encoding.y = stream[offset+2]<<8&stream[offset+3];

				return Encoding;
			}
			public new static uint getRequiredStreamSize(uint h, uint w, int bpp) {			
				return 4;
			}

		}
		
		public class Raw : AbstractRFBEncoding {
			public new string type = "Raw";
			public new static Raw fromStream(uint h, uint w, int bpp, int offset, byte[] stream) {
				Raw Encoding = new Raw();
				int length =(int) (h*w* bpp/8);
				Encoding.pixels = new byte[length];
				try {
					Array.Copy(stream,offset+4,Encoding.pixels,0,length);
				} catch(Exception e) {}
				return Encoding;
			}
			
			public new static uint getRequiredStreamSize(uint h, uint w, int bpp) {			
				return (uint) (h*w*bpp/8);
			}
		}
		
		public class Cursor : AbstractRFBEncoding {
			public new string type = "Cursor";
			public byte[] bitmask;
			public new static Cursor fromStream(uint h, uint w, int bpp, int offset, byte[] stream) {
				Cursor Encoding = new Cursor();
				int length = (int) (h*w*bpp/8);
				int bitmaskLength = (int) Math.Floor((double)((int)w+7)*8)+(int)h;

				Encoding.pixels = new byte[length];
				Encoding.bitmask = new byte[bitmaskLength];
				
				Array.Copy(stream,offset,Encoding.pixels,0,length);	
				Array.Copy(stream,offset+length,Encoding.bitmask,0,bitmaskLength);
				return Encoding;
			}
			
			public new static uint getRequiredStreamSize(uint h, uint w, int bpp) {			
				return (uint) (h*w*bpp/8);
			}
		}
		
		public static uint getEncodingSize(uint h, uint w, int bpp, int offset,byte[] stream) {
			int nr = 0; 
			nr |= (int) (stream[offset]);
			nr |= (int) (stream[offset+1])<<8;
			nr |= (int) (stream[offset+2])<<16;
			nr |= (int) (stream[offset+3])<<24;
			switch(nr) {
				case 0:
					return RFBEncoding.Raw.getRequiredStreamSize(h,w,bpp);
					break;
				case -239:
					return RFBEncoding.Cursor.getRequiredStreamSize(h,w,bpp);
					break;
			}
			return 0;	
		}
		
		public static AbstractRFBEncoding getEncoding(uint h, uint w, int bpp, int offset, byte[] stream) {
			int nr = 0; 
			nr |= (int) (stream[offset]);
			nr |= (int) (stream[offset+1])<<8;
			nr |= (int) (stream[offset+2])<<16;
			nr |= (int) (stream[offset+3])<<24;
			switch(nr) {
				case 0:
					return RFBEncoding.Raw.fromStream(h,w,bpp,offset,stream);
					break;
				case -239:
					return RFBEncoding.Cursor.fromStream(h,w,bpp,offset,stream);
					break;
			}
			return null;
		}
		/*
		public class CopyRect {
			public static Raw fromStream(int h, int w, int bpp, int offset, byte[] stream) {
				int length = h*w*bpp;
				pixels = new byte[length];
				
				Array.Copy(stream,offset,pixels,0,length);
			}
			
		}*/
	}
}

